package com.rickpan.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rickpan.entity.GeneratedReport;
import com.rickpan.entity.WorkRecord;
import com.rickpan.entity.WorkStatistics;
import com.rickpan.repository.GeneratedReportRepository;
import com.rickpan.repository.WorkRecordRepository;
import com.rickpan.repository.WorkStatisticsRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 工作统计服务
 * 提供工作数据的统计分析功能
 */
@Service
public class WorkStatisticsService {

    private static final Logger logger = LoggerFactory.getLogger(WorkStatisticsService.class);

    @Autowired
    private WorkStatisticsRepository workStatisticsRepository;

    @Autowired
    private WorkRecordRepository workRecordRepository;

    @Autowired
    private GeneratedReportRepository generatedReportRepository;

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 生成用户的日统计数据
     */
    @Transactional
    public WorkStatistics generateDailyStatistics(Long userId, LocalDate date) {
        logger.info("生成日统计数据，用户ID: {}, 日期: {}", userId, date);

        // 检查是否已存在统计数据
        Optional<WorkStatistics> existingStats = workStatisticsRepository
            .findByUserIdAndStatDateAndStatType(userId, date, WorkStatistics.StatType.DAILY);

        WorkStatistics statistics;
        if (existingStats.isPresent()) {
            statistics = existingStats.get();
        } else {
            statistics = new WorkStatistics(userId, date, WorkStatistics.StatType.DAILY);
        }

        // 获取当日工作记录
        List<WorkRecord> dayRecords = workRecordRepository.findByUserIdAndDate(userId, date);

        // 计算基础统计
        calculateBasicStats(statistics, dayRecords);

        // 计算分类统计
        calculateCategoryStats(statistics, dayRecords);

        // 计算优先级统计
        calculatePriorityStats(statistics, dayRecords);

        // 计算报告统计
        calculateReportStats(statistics, userId, date, date);

        // 计算效率指标
        statistics.calculateCompletionRate();
        statistics.calculateAvgTimeSpent();
        statistics.calculateEfficiencyScore();

        return workStatisticsRepository.save(statistics);
    }

    /**
     * 生成用户的周统计数据
     */
    @Transactional
    public WorkStatistics generateWeeklyStatistics(Long userId, LocalDate weekStart) {
        logger.info("生成周统计数据，用户ID: {}, 周开始日期: {}", userId, weekStart);

        LocalDate weekEnd = weekStart.plusDays(6);
        
        Optional<WorkStatistics> existingStats = workStatisticsRepository
            .findByUserIdAndStatDateAndStatType(userId, weekStart, WorkStatistics.StatType.WEEKLY);

        WorkStatistics statistics;
        if (existingStats.isPresent()) {
            statistics = existingStats.get();
        } else {
            statistics = new WorkStatistics(userId, weekStart, WorkStatistics.StatType.WEEKLY);
        }

        // 获取周内工作记录
        List<WorkRecord> weekRecords = workRecordRepository.findByUserIdAndDateBetween(userId, weekStart, weekEnd);

        // 计算统计数据
        calculateBasicStats(statistics, weekRecords);
        calculateCategoryStats(statistics, weekRecords);
        calculatePriorityStats(statistics, weekRecords);
        calculateReportStats(statistics, userId, weekStart, weekEnd);

        statistics.calculateCompletionRate();
        statistics.calculateAvgTimeSpent();
        statistics.calculateEfficiencyScore();

        return workStatisticsRepository.save(statistics);
    }

    /**
     * 生成用户的月统计数据
     */
    @Transactional
    public WorkStatistics generateMonthlyStatistics(Long userId, LocalDate monthStart) {
        logger.info("生成月统计数据，用户ID: {}, 月开始日期: {}", userId, monthStart);

        LocalDate monthEnd = monthStart.withDayOfMonth(monthStart.lengthOfMonth());
        
        Optional<WorkStatistics> existingStats = workStatisticsRepository
            .findByUserIdAndStatDateAndStatType(userId, monthStart, WorkStatistics.StatType.MONTHLY);

        WorkStatistics statistics;
        if (existingStats.isPresent()) {
            statistics = existingStats.get();
        } else {
            statistics = new WorkStatistics(userId, monthStart, WorkStatistics.StatType.MONTHLY);
        }

        // 获取月内工作记录
        List<WorkRecord> monthRecords = workRecordRepository.findByUserIdAndDateBetween(userId, monthStart, monthEnd);

        // 计算统计数据
        calculateBasicStats(statistics, monthRecords);
        calculateCategoryStats(statistics, monthRecords);
        calculatePriorityStats(statistics, monthRecords);
        calculateReportStats(statistics, userId, monthStart, monthEnd);

        statistics.calculateCompletionRate();
        statistics.calculateAvgTimeSpent();
        statistics.calculateEfficiencyScore();

        return workStatisticsRepository.save(statistics);
    }

    /**
     * 获取用户统计数据概览
     */
    public Map<String, Object> getUserStatisticsOverview(Long userId) {
        Map<String, Object> overview = new HashMap<>();

        // 总工作记录数
        Long totalRecords = workStatisticsRepository.getTotalWorkRecordsByUser(userId);
        overview.put("totalRecords", totalRecords);

        // 总工时
        Long totalTimeSpent = workStatisticsRepository.getTotalTimeSpentByUser(userId);
        overview.put("totalTimeSpent", totalTimeSpent);

        // 最近30天平均完成率
        LocalDate thirtyDaysAgo = LocalDate.now().minusDays(30);
        Double avgCompletionRate = workStatisticsRepository.getAvgCompletionRateByUser(userId, thirtyDaysAgo);
        overview.put("avgCompletionRate", avgCompletionRate);

        // 最近30天平均效率评分
        Double avgEfficiencyScore = workStatisticsRepository.getAvgEfficiencyScoreByUser(userId, thirtyDaysAgo);
        overview.put("avgEfficiencyScore", avgEfficiencyScore);

        // 最近7天趋势
        LocalDate sevenDaysAgo = LocalDate.now().minusDays(7);
        List<WorkStatistics> recentStats = workStatisticsRepository.getDailyStatsByDateRange(userId, sevenDaysAgo, LocalDate.now());
        overview.put("recentTrend", recentStats);

        return overview;
    }

    /**
     * 获取用户工作趋势数据
     */
    public Map<String, Object> getUserWorkTrends(Long userId, String period) {
        Map<String, Object> trends = new HashMap<>();
        LocalDate startDate;

        switch (period.toLowerCase()) {
            case "week":
                startDate = LocalDate.now().minusWeeks(4);
                List<Object[]> weeklyTrends = workStatisticsRepository.getWorkTrendsByWeek(userId, startDate);
                trends.put("data", weeklyTrends);
                trends.put("period", "weekly");
                break;
            case "month":
                startDate = LocalDate.now().minusMonths(12);
                List<Object[]> monthlyTrends = workStatisticsRepository.getWorkTrendsByMonth(userId, startDate);
                trends.put("data", monthlyTrends);
                trends.put("period", "monthly");
                break;
            default:
                startDate = LocalDate.now().minusDays(30);
                List<WorkStatistics> dailyTrends = workStatisticsRepository.getDailyStatsByDateRange(userId, startDate, LocalDate.now());
                trends.put("data", dailyTrends);
                trends.put("period", "daily");
        }

        return trends;
    }

    /**
     * 获取用户分类统计汇总
     */
    public Map<String, Integer> getUserCategoryStatsSummary(Long userId) {
        LocalDate thirtyDaysAgo = LocalDate.now().minusDays(30);
        List<String> categoryStatsJson = workStatisticsRepository.getCategoryStatsByUser(userId, thirtyDaysAgo);
        
        Map<String, Integer> summary = new HashMap<>();
        
        for (String json : categoryStatsJson) {
            try {
                Map<String, Integer> stats = objectMapper.readValue(json, new TypeReference<Map<String, Integer>>() {});
                for (Map.Entry<String, Integer> entry : stats.entrySet()) {
                    summary.merge(entry.getKey(), entry.getValue(), Integer::sum);
                }
            } catch (JsonProcessingException e) {
                logger.warn("解析分类统计JSON失败: {}", json, e);
            }
        }
        
        return summary;
    }

    /**
     * 获取用户优先级统计汇总
     */
    public Map<String, Integer> getUserPriorityStatsSummary(Long userId) {
        LocalDate thirtyDaysAgo = LocalDate.now().minusDays(30);
        List<String> priorityStatsJson = workStatisticsRepository.getPriorityStatsByUser(userId, thirtyDaysAgo);
        
        Map<String, Integer> summary = new HashMap<>();
        
        for (String json : priorityStatsJson) {
            try {
                Map<String, Integer> stats = objectMapper.readValue(json, new TypeReference<Map<String, Integer>>() {});
                for (Map.Entry<String, Integer> entry : stats.entrySet()) {
                    summary.merge(entry.getKey(), entry.getValue(), Integer::sum);
                }
            } catch (JsonProcessingException e) {
                logger.warn("解析优先级统计JSON失败: {}", json, e);
            }
        }
        
        return summary;
    }

    /**
     * 批量生成缺失的统计数据
     */
    @Transactional
    public void generateMissingStatistics(Long userId) {
        logger.info("批量生成缺失的统计数据，用户ID: {}", userId);

        // 获取需要生成统计数据的日期
        List<LocalDate> missingDates = workStatisticsRepository.getMissingStatDates(userId);
        
        for (LocalDate date : missingDates) {
            try {
                generateDailyStatistics(userId, date);
            } catch (Exception e) {
                logger.error("生成日统计数据失败，用户ID: {}, 日期: {}", userId, date, e);
            }
        }

        // 生成周统计数据
        LocalDate now = LocalDate.now();
        LocalDate weekStart = now.minusDays(now.getDayOfWeek().getValue() - 1);
        for (int i = 0; i < 12; i++) {
            LocalDate currentWeekStart = weekStart.minusWeeks(i);
            try {
                generateWeeklyStatistics(userId, currentWeekStart);
            } catch (Exception e) {
                logger.error("生成周统计数据失败，用户ID: {}, 周开始: {}", userId, currentWeekStart, e);
            }
        }

        // 生成月统计数据
        LocalDate monthStart = now.withDayOfMonth(1);
        for (int i = 0; i < 12; i++) {
            LocalDate currentMonthStart = monthStart.minusMonths(i);
            try {
                generateMonthlyStatistics(userId, currentMonthStart);
            } catch (Exception e) {
                logger.error("生成月统计数据失败，用户ID: {}, 月开始: {}", userId, currentMonthStart, e);
            }
        }
    }

    // ==================== 私有方法 ====================

    /**
     * 计算基础统计数据
     */
    private void calculateBasicStats(WorkStatistics statistics, List<WorkRecord> records) {
        statistics.setTotalRecords(records.size());
        
        Map<WorkRecord.Status, Long> statusCounts = records.stream()
            .collect(Collectors.groupingBy(WorkRecord::getStatus, Collectors.counting()));
        
        statistics.setCompletedRecords(statusCounts.getOrDefault(WorkRecord.Status.COMPLETED, 0L).intValue());
        statistics.setInProgressRecords(statusCounts.getOrDefault(WorkRecord.Status.IN_PROGRESS, 0L).intValue());
        statistics.setPendingRecords(statusCounts.getOrDefault(WorkRecord.Status.PENDING, 0L).intValue());
        statistics.setCancelledRecords(statusCounts.getOrDefault(WorkRecord.Status.CANCELLED, 0L).intValue());
        
        // 计算时间统计
        int totalTime = records.stream().mapToInt(r -> r.getTimeSpent() != null ? r.getTimeSpent() : 0).sum();
        statistics.setTotalTimeSpent(totalTime);
        
        if (!records.isEmpty()) {
            OptionalInt maxTime = records.stream().mapToInt(r -> r.getTimeSpent() != null ? r.getTimeSpent() : 0).max();
            OptionalInt minTime = records.stream().mapToInt(r -> r.getTimeSpent() != null ? r.getTimeSpent() : 0).min();
            
            statistics.setMaxTimeSpent(maxTime.orElse(0));
            statistics.setMinTimeSpent(minTime.orElse(0));
        }
    }

    /**
     * 计算分类统计
     */
    private void calculateCategoryStats(WorkStatistics statistics, List<WorkRecord> records) {
        Map<String, Long> categoryStats = records.stream()
            .filter(r -> r.getCategory() != null)
            .collect(Collectors.groupingBy(r -> r.getCategory().getName(), Collectors.counting()));
        
        try {
            String categoryStatsJson = objectMapper.writeValueAsString(categoryStats);
            statistics.setCategoryStats(categoryStatsJson);
        } catch (JsonProcessingException e) {
            logger.warn("序列化分类统计失败", e);
        }
    }

    /**
     * 计算优先级统计
     */
    private void calculatePriorityStats(WorkStatistics statistics, List<WorkRecord> records) {
        Map<String, Long> priorityStats = records.stream()
            .collect(Collectors.groupingBy(r -> r.getPriority().name(), Collectors.counting()));
        
        try {
            String priorityStatsJson = objectMapper.writeValueAsString(priorityStats);
            statistics.setPriorityStats(priorityStatsJson);
        } catch (JsonProcessingException e) {
            logger.warn("序列化优先级统计失败", e);
        }
    }

    /**
     * 计算报告统计
     */
    private void calculateReportStats(WorkStatistics statistics, Long userId, LocalDate startDate, LocalDate endDate) {
        List<GeneratedReport> reports = generatedReportRepository.findByUserIdAndPeriodStartBetweenOrderByCreatedAtDesc(
            userId, startDate, endDate, PageRequest.of(0, 1000)).getContent();
        
        Map<GeneratedReport.ReportType, Long> reportCounts = reports.stream()
            .collect(Collectors.groupingBy(GeneratedReport::getType, Collectors.counting()));
        
        statistics.setDailyReportsCount(reportCounts.getOrDefault(GeneratedReport.ReportType.DAILY, 0L).intValue());
        statistics.setWeeklyReportsCount(reportCounts.getOrDefault(GeneratedReport.ReportType.WEEKLY, 0L).intValue());
        statistics.setMonthlyReportsCount(reportCounts.getOrDefault(GeneratedReport.ReportType.MONTHLY, 0L).intValue());
    }
}
